﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using System.Collections.ObjectModel;

namespace Pavilion
{
    public delegate void ItemReplacedHandler<T>(T oldItem, T newItem, int index);
    /// <summary>
    /// As ObservableCollection that provides specific events for Adding and Removing from the collection
    /// </summary>
    public class NotifiableCollection<T> : ObservableCollection<T>, IMovableCollection
    {
        public event Action<T, int> Added, Removed;
        public event ItemReplacedHandler<T> Replaced;
        public event Action<int, int> Moved;

        public NotifiableCollection() : base() { }
        public NotifiableCollection(IEnumerable<T> collection) : base(collection) { }
        public NotifiableCollection(List<T> list) : base(list) { }

        protected override void MoveItem(int oldIndex, int newIndex)
        {
            base.MoveItem(oldIndex, newIndex);
            OnMoved(oldIndex, newIndex);
        }

        /// <summary>
        /// Adds a collection of items to this collection.
        /// </summary>
        /// <param name="collection"></param>
        public void AddRange(IEnumerable<T> collection)
        {
            foreach (T item in collection)
                Add(item);
        }

        new public void Clear()
        {
            while (Count != 0)
                RemoveAt(0);
        }

        protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action != System.Collections.Specialized.NotifyCollectionChangedAction.Move && e.Action != System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
            {
                if (e.NewItems != null)
                {
                    if (e.NewItems.Count > 1)
                        throw new NotImplementedException("This collection has not implemented the ability to notify of the adding of large amount of items.");

                    OnAdded((T)e.NewItems[0], e.NewStartingIndex);
                }

                if (e.OldItems != null)
                {
                    if (e.OldItems.Count > 1)
                        throw new NotImplementedException("This collection has not implemented the ability to notify of the removal of large amount of items.");

                    OnRemoved((T)e.OldItems[0], e.OldStartingIndex);
                }
            }

            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Replace)
            {
                if (e.OldItems.Count > 1)
                        throw new NotImplementedException("This collection has not implemented the ability to notify of the removal of large amount of items.");
                if (e.NewItems.Count > 1)
                        throw new NotImplementedException("This collection has not implemented the ability to notify of the adding of large amount of items.");

                OnReplaced((T)e.OldItems[0], (T)e.NewItems[0], e.NewStartingIndex);
            }

            base.OnCollectionChanged(e);
        }

        protected void OnRemoved(T item, int index)
        {
            if (Removed != null)
                Removed(item, index);
        }

        protected void OnAdded(T item, int index)
        {
            if (Added != null)
                Added(item, index);
        }

        private void OnMoved(int oldIndex, int newIndex)
        {
            if (Moved != null)
                Moved(oldIndex, newIndex);
        }

        private void OnReplaced(T oldItem, T newItem, int index)
        {
            if (Replaced != null)
                Replaced(oldItem, newItem, index);
        }
    }
}
